using Godot;
using System;
using Common;
using File = Common.File;
using System.Collections.Generic;

namespace Library {
	public class StorageManager : IRegisterManager<Storage> {
		Dictionary<string,Storage> storages=new Dictionary<string, Storage>();
		public void Register(Storage storage){
			if (IsExists(storage.Id)) {
				throw new ArgumentException("A storage with the same ID: " + storage.Id + " is already registered!");
			}
			storages.Add(storage.Id, storage);
		}
		public bool IsExists(string id)=>storages.ContainsKey(id);
		public Storage Get(string id)=>IsExists(id)?storages[id]:null;
		public void Remove(string id)=>storages.Remove(id);
		public void Clear()=>storages.Clear();
		public Storage this[string id] => Get(id);
	}
	public class Storage : IRegisterable {
		/// <summary>
		/// Initiate a <c>Storage</c> with the given path.
		/// </summary>
		/// <param name="path">Save/load path.</param>
		public Storage(string id, string path) {
			Id = id;
			Path = path;
		}

		/// <summary>
		/// Unique identifier for this storage.
		/// </summary>
		public string Id { get; }

		string rawPath = "";
		/// <summary>
		/// The path of the storage file.
		/// Insert <c>{0}</c> for slot number placeholder.
		/// </summary>
		public string Path {
			set => rawPath = value;
			get => string.Format(rawPath, Slot);
		}
		public int Slot { get; set; } = 0;

		/// <summary>
		/// The data of the storage.
		/// </summary>
		public ComplexValue.Dictionary Root { get; private set; }

		/// <summary>
		/// Save the storage to <c>Path</c>.
		/// </summary>
		/// <exception cref="Exception">See <c>Game.File.Save()</c> for exception information.</exception>
		public void Save() {
			File file = File.Open(Path, File.OpenMode.TruncateWrite);
			file.WriteBytes(Root.SerializeBinary());
			file.Close();
		}

		/// <summary>
		/// Load the storage from <see>
		/// </summary>
		/// <exception cref="FormatException">The loaded <c>ComplexValue</c> cannot be intepreted as a <c>ComplexValue.Dictionary</c>.</exception>
		/// <exception cref="Exception">See <c>Game.File.Open()</c> for exception information.</exception>
		public void Load() {
			File file = File.Open(Path, File.OpenMode.Read);
			byte[] data = file.ReadAllBytes();
			file.Close();
			ComplexValue result = null;
			ComplexValue.DeserializeBinary(data, 0, out result);
			if (!result.IsDictionary) {
				throw new FormatException("The loaded storage cannot be intepreted as a ComplexValue.Dictionary.");
			}
			Root = result.AsDictionary();
		}
	}
}
